#pragma once

#include <brpc/channel.h>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <mutex>
#include "logger.h"

// 单个服务信道管理类
class ServiceChannel
{
public:
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
    using Ptr = std::shared_ptr<ServiceChannel>;

public:
    ServiceChannel(const std::string &name) : _service_name(name), _index(0)
    {
    }

    // 添加信道
    void addChannel(const std::string &host)
    {
        auto channel = std::make_shared<brpc::Channel>();
        // 设置信道的option, -1为不会超时
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1;
        options.timeout_ms = -1;
        options.max_retry = 3;
        options.protocol = "baidu_std";

        int ret = channel->Init(host.c_str(), &options);
        if (ret == -1)
        {
            LOG_ERROR("初始化{}-{}信道失败!", _service_name, host);
            return;
        }

        // 将信道放入vector中进行管理, 并添加映射关系
        std::unique_lock<std::mutex> lock(_mtx);
        _hosts.insert(std::make_pair(host, channel));
        _channels.push_back(channel);
    }

    // 删除信道
    void delChannel(const std::string &host)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        // 查找要删除的信道
        auto hosts_it = _hosts.find(host);
        if (hosts_it == _hosts.end())
        {
            LOG_WARN("{}-{}节点删除信道时，没有找到信道信息", _service_name, host);
            return;
        }
        // 从vector中删除
        for (auto vit = _channels.begin(); vit != _channels.end(); ++vit)
        {
            if (*vit == hosts_it->second)
            {
                _channels.erase(vit);
                break;
            }
        }
        // 删除映射关系
        _hosts.erase(hosts_it);
    }

    // 获取信道 使用轮转策略
    ChannelPtr getChannel()
    {
        std::unique_lock<std::mutex> lock(_mtx);
        if (_channels.size() == 0)
        {
            LOG_ERROR("当前没有能够提供 {} 服务的节点", _service_name);
            return ChannelPtr();
        }
        int idx = _index++ % _channels.size();
        _index %= _channels.size();
        return _channels[idx];
    }

    ~ServiceChannel()
    {
    }

private:
    std::string _service_name;                          // 服务名称
    std::vector<ChannelPtr> _channels;                  // 该服务的信道数组
    std::unordered_map<std::string, ChannelPtr> _hosts; // 主机地址和信道映射关系

    std::mutex _mtx;
    int _index; // 轮转下标
};

// 总体服务信道管理类
class ServiceManager
{
public:
    using ptr = std::shared_ptr<ServiceManager>;

    ServiceManager()
    {
    }

    // 获取指定服务
    ServiceChannel::ChannelPtr getService(const std::string &service_name)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        auto service_it = _services.find(service_name);
        if (service_it == _services.end())
        {
            LOG_ERROR("当前没有能够提供 {} 服务的节点", service_name);
            return ServiceChannel::ChannelPtr();
        }
        return service_it->second->getChannel();
    }

    // 添加关心服务
    void addCareService(const std::string &service_name)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        _care_services.insert(service_name);
    }

    // 添加服务 -- 服务上线时回调
    void addService(const std::string &total_name, const std::string &host)
    {
        std::string service_name = getServiceName(total_name);
        ServiceChannel::Ptr service;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            // 先判断是否为关心的服务上线
            auto care_it = _care_services.find(service_name);
            if (care_it == _care_services.end())
            {
                LOG_DEBUG("{}-{} 服务上线了，但是当前并不关心", service_name, host);
                return;
            }

            // 再判断该服务的信道管理对象是否存在, 不存在创建, 存在往该对象添加信道即可
            auto service_it = _services.find(service_name);
            if (service_it == _services.end())
            {
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert(std::make_pair(service_name, service));
            }
            else
            {
                service = service_it->second;
            }
        }

        if (!service)
        {
            LOG_ERROR("新增 {} 服务管理节点失败", service_name);
            return;
        }

        service->addChannel(host);
        LOG_DEBUG("{}-{} 服务上线新节点，进行添加管理", service_name, host);
    }

    // 删除服务 -- 服务下线回调
    void delService(const std::string &total_name, const std::string &host)
    {
        std::string service_name = getServiceName(total_name);
        ServiceChannel::Ptr service;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            // 先判断是否为关心的服务下线
            auto care_it = _care_services.find(service_name);
            if (care_it == _care_services.end())
            {
                LOG_DEBUG("{}-{} 服务下线了，但是当前并不关心", service_name, host);
                return;
            }

            // 获取下线服务管理对象
            auto service_it = _services.find(service_name);
            if (service_it == _services.end())
            {
                LOG_WARN("删除{}服务节点时，没有找到管理对象", service_name);
                return;
            }
        }

        service->delChannel(host);
        LOG_DEBUG("{}-{} 服务下线节点，进行删除管理", service_name, host);
    }

    ~ServiceManager()
    {
    }

private:
    std::string getServiceName(const std::string &total_name)
    {
        auto pos = total_name.find_last_of('/');
        if(pos == std::string::npos)
            return total_name;
        return total_name.substr(0, pos);
    }

private:
    std::mutex _mtx;
    std::unordered_map<std::string, ServiceChannel::Ptr> _services; // 服务名与其信道映射关系
    std::unordered_set<std::string> _care_services;                 // 关心服务上线和下线的服务集合
};